/*     */ package com.zimbra.cs.service.authenticator;
/*     */ 
/*     */ import com.zimbra.common.account.Key.AccountBy;
/*     */ import com.zimbra.common.localconfig.DebugConfig;
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.ByteUtil;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.Server;
/*     */ import java.io.File;
/*     */ import java.io.FileInputStream;
/*     */ import java.io.FileNotFoundException;
/*     */ import java.io.FileOutputStream;
/*     */ import java.io.IOException;
/*     */ import java.io.OutputStreamWriter;
/*     */ import java.io.Writer;
/*     */ import java.nio.charset.Charset;
/*     */ import java.security.InvalidAlgorithmParameterException;
/*     */ import java.security.KeyStore;
/*     */ import java.security.KeyStoreException;
/*     */ import java.security.NoSuchAlgorithmException;
/*     */ import java.security.Principal;
/*     */ import java.security.cert.CertPath;
/*     */ import java.security.cert.CertPathValidator;
/*     */ import java.security.cert.CertPathValidatorException;
/*     */ import java.security.cert.CertificateEncodingException;
/*     */ import java.security.cert.CertificateException;
/*     */ import java.security.cert.CertificateExpiredException;
/*     */ import java.security.cert.CertificateFactory;
/*     */ import java.security.cert.CertificateNotYetValidException;
/*     */ import java.security.cert.PKIXCertPathValidatorResult;
/*     */ import java.security.cert.PKIXParameters;
/*     */ import java.security.cert.TrustAnchor;
/*     */ import java.security.cert.X509Certificate;
/*     */ import java.text.SimpleDateFormat;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Date;
/*     */ import java.util.Enumeration;
/*     */ import java.util.HashSet;
/*     */ import java.util.List;
/*     */ import java.util.Set;
/*     */ import javax.naming.InvalidNameException;
/*     */ import javax.naming.ldap.LdapName;
/*     */ import javax.naming.ldap.Rdn;
/*     */ import javax.servlet.http.HttpServletRequest;
/*     */ import javax.servlet.http.HttpServletResponse;
/*     */ import sun.misc.BASE64Encoder;
/*     */ import sun.security.x509.AuthorityInfoAccessExtension;
/*     */ import sun.security.x509.X509CertImpl;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class ClientCertAuthenticator
/*     */   extends SSOAuthenticator
/*     */ {
/*     */   static final String LOG_PREFIX = "certauth - ";
/*     */   
/*     */   public ClientCertAuthenticator(HttpServletRequest req, HttpServletResponse resp)
/*     */   {
/*  78 */     super(req, resp);
/*     */   }
/*     */   
/*     */   public String getAuthType()
/*     */   {
/*  83 */     return "ClientCert";
/*     */   }
/*     */   
/*     */   public SSOAuthenticator.ZimbraPrincipal authenticate() throws ServiceException
/*     */   {
/*  88 */     X509Certificate cert = getCert();
/*     */     
/*  90 */     if (DebugConfig.certAuthCaptureClientCertificate) {
/*  91 */       captureClientCert(cert);
/*     */     }
/*     */     
/*  94 */     ClientCertPrincipalMap principalMap = new ClientCertPrincipalMap(this.req);
/*  95 */     List<ClientCertPrincipalMap.Rule> rules = principalMap.getRules();
/*     */     
/*  97 */     for (ClientCertPrincipalMap.Rule rule : rules) {
/*     */       try {
/*  99 */         ZimbraLog.account.debug("certauth - Attempting rule " + rule.getName());
/* 100 */         SSOAuthenticator.ZimbraPrincipal zimbraPrincipal = rule.apply(cert);
/* 101 */         if (zimbraPrincipal != null) {
/* 102 */           return zimbraPrincipal;
/*     */         }
/* 104 */         ZimbraLog.account.debug("certauth - Rule " + rule.getName() + " not matched");
/*     */       }
/*     */       catch (ServiceException e) {
/* 107 */         ZimbraLog.account.debug("certauth - Rule " + rule.getName() + " not matched", e);
/*     */       }
/*     */     }
/*     */     
/* 111 */     throw AccountServiceException.AuthFailedServiceException.AUTH_FAILED(cert.toString(), "ClientCertAuthenticator - no matching Zimbra principal from client certificate.", (Throwable)null);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private void captureClientCert(X509Certificate cert)
/*     */   {
/* 121 */     SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd-HHmmss.S");
/* 122 */     FileOutputStream os = null;
/* 123 */     Writer wr = null;
/*     */     try {
/* 125 */       File file = new File(LC.zimbra_tmp_directory.value() + "/clientcert." + fmt.format(new Date()));
/*     */       
/*     */ 
/* 128 */       byte[] buf = cert.getEncoded();
/*     */       
/* 130 */       os = new FileOutputStream(file);
/*     */       
/* 132 */       wr = new OutputStreamWriter(os, Charset.forName("UTF-8"));
/* 133 */       wr.write("-----BEGIN CERTIFICATE-----\n");
/* 134 */       wr.write(new BASE64Encoder().encode(buf));
/* 135 */       wr.write("\n-----END CERTIFICATE-----\n");
/* 136 */       wr.flush();
/*     */     } catch (CertificateEncodingException e) {
/* 138 */       ZimbraLog.account.debug("certauth - unable to capture cert", e);
/*     */     } catch (IOException e) {
/* 140 */       ZimbraLog.account.debug("certauth - unable to capture cert", e);
/*     */     } finally {
/* 142 */       ByteUtil.closeWriter(wr);
/* 143 */       ByteUtil.closeStream(os);
/*     */     }
/*     */   }
/*     */   
/*     */   private X509Certificate getCert() throws ServiceException {
/* 148 */     X509Certificate[] certs = (X509Certificate[])this.req.getAttribute("javax.servlet.request.X509Certificate");
/*     */     
/* 150 */     if ((certs == null) || (certs.length == 0) || (certs[0] == null)) {
/* 151 */       throw SSOAuthenticator.SSOAuthenticatorServiceException.NO_CLIENT_CERTIFICATE();
/*     */     }
/*     */     
/* 154 */     validateClientCert(certs);
/*     */     
/* 156 */     return certs[0];
/*     */   }
/*     */   
/*     */   public static Account getAccountByX509SubjectDN(String x509SubjectDN) throws ServiceException
/*     */   {
/*     */     try {
/* 162 */       LdapName dn = new LdapName(x509SubjectDN);
/* 163 */       List<Rdn> rdns = dn.getRdns();
/*     */       
/* 165 */       for (Rdn rdn : rdns) {
/* 166 */         String type = rdn.getType();
/*     */         
/*     */ 
/* 169 */         if ("EMAILADDRESS".equals(type)) {
/* 170 */           Object value = rdn.getValue();
/* 171 */           if (value != null) {
/* 172 */             String email = value.toString();
/* 173 */             Account acct = Provisioning.getInstance().get(Key.AccountBy.name, email);
/* 174 */             if (acct != null) {
/* 175 */               return acct;
/*     */             }
/* 177 */             ZimbraLog.account.debug("certauth - account not found: " + email);
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/*     */     catch (InvalidNameException e) {
/* 183 */       throw AccountServiceException.AuthFailedServiceException.AUTH_FAILED("ClientCertAuthenticator - invalid X509 subject: " + x509SubjectDN, e);
/*     */     }
/*     */     
/* 186 */     return null;
/*     */   }
/*     */   
/*     */   private String getSubjectDNForLogging(X509Certificate cert) {
/* 190 */     String subjectDn = null;
/* 191 */     Principal principal = cert.getSubjectDN();
/* 192 */     if (principal != null) {
/* 193 */       subjectDn = principal.getName();
/*     */     }
/*     */     
/* 196 */     if (subjectDn == null) {
/* 197 */       subjectDn = "";
/*     */     }
/*     */     
/* 200 */     return subjectDn;
/*     */   }
/*     */   
/*     */   private void validateClientCert(X509Certificate[] certs) throws ServiceException {
/* 204 */     for (X509Certificate cert : certs) {
/* 205 */       FileInputStream fis = null;
/*     */       try {
/* 207 */         cert.checkValidity();
/*     */         
/* 209 */         boolean revocationCheckEnabled = Provisioning.getInstance().getLocalServer().isMailSSLClientCertOCSPEnabled();
/* 210 */         if (revocationCheckEnabled) {
/* 211 */           ZimbraLog.account.debug("certauth - found AuthorityInfoAccess extension in client certificate");
/* 212 */           List<X509Certificate> certificates = new ArrayList();
/* 213 */           certificates.add(cert);
/*     */           
/* 215 */           CertificateFactory cf = CertificateFactory.getInstance("X509");
/* 216 */           CertPath cp = cf.generateCertPath(certificates);
/*     */           
/* 218 */           KeyStore ks = KeyStore.getInstance("JKS");
/* 219 */           char[] pass = LC.client_ssl_truststore_password.value().toCharArray();
/* 220 */           fis = new FileInputStream(LC.client_ssl_truststore.value());
/* 221 */           ks.load(fis, pass);
/*     */           
/* 223 */           Set<TrustAnchor> trustedCertsSet = new HashSet();
/* 224 */           Enumeration<String> aliases = ks.aliases();
/* 225 */           while (aliases.hasMoreElements()) {
/* 226 */             String alias = (String)aliases.nextElement();
/*     */             
/* 228 */             X509Certificate rootCACert = (X509Certificate)ks.getCertificate(alias);
/* 229 */             TrustAnchor ta = new TrustAnchor(rootCACert, null);
/* 230 */             trustedCertsSet.add(ta);
/*     */             
/* 232 */             ZimbraLog.account.debug("certauth - adding certificate with issuer DN:" + rootCACert.getIssuerDN().toString() + " signature name:" + rootCACert.getSigAlgName());
/*     */           }
/*     */           
/*     */ 
/* 236 */           PKIXParameters params = new PKIXParameters(trustedCertsSet);
/*     */           
/* 238 */           params.setRevocationEnabled(revocationCheckEnabled);
/*     */           
/*     */ 
/* 241 */           CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
/* 242 */           PKIXCertPathValidatorResult cpv_result = (PKIXCertPathValidatorResult)cpv.validate(cp, params);
/*     */           
/* 244 */           ZimbraLog.account.debug("certauth - " + cpv_result.toString());
/*     */         }
/*     */       } catch (CertificateExpiredException e) {
/* 247 */         throw AccountServiceException.AuthFailedServiceException.AUTH_FAILED(getSubjectDNForLogging(cert), "client certificate expired", e);
/*     */       } catch (CertificateNotYetValidException e) {
/* 249 */         throw AccountServiceException.AuthFailedServiceException.AUTH_FAILED(getSubjectDNForLogging(cert), "client certificate not yet valid", e);
/*     */       } catch (CertificateException e) {
/* 251 */         throw AccountServiceException.AuthFailedServiceException.AUTH_FAILED(getSubjectDNForLogging(cert), "can't generate certpath for client certificate", e);
/*     */       } catch (KeyStoreException e) {
/* 253 */         throw AccountServiceException.AuthFailedServiceException.AUTH_FAILED(getSubjectDNForLogging(cert), "received KeyStoreException while loading KeyStore", e);
/*     */       } catch (NoSuchAlgorithmException e) {
/* 255 */         throw AccountServiceException.AuthFailedServiceException.AUTH_FAILED(getSubjectDNForLogging(cert), "received NoSuchAlgorithmException while obtaining instance of certpath validator", e);
/*     */       } catch (FileNotFoundException e) {
/* 257 */         throw AccountServiceException.AuthFailedServiceException.AUTH_FAILED(getSubjectDNForLogging(cert), "mailboxd keystore can't be found", e);
/*     */       } catch (IOException e) {
/* 259 */         throw AccountServiceException.AuthFailedServiceException.AUTH_FAILED(getSubjectDNForLogging(cert), "received IOException", e);
/*     */       } catch (InvalidAlgorithmParameterException e) {
/* 261 */         throw AccountServiceException.AuthFailedServiceException.AUTH_FAILED(getSubjectDNForLogging(cert), "received InvalidAlgorithmParameter while obtaining instance of certpath validator", e);
/*     */       } catch (CertPathValidatorException e) {
/* 263 */         throw AccountServiceException.AuthFailedServiceException.AUTH_FAILED(getSubjectDNForLogging(cert), "received CertPathValidatorException" + e.getMessage(), e);
/*     */       } finally {
/* 265 */         ByteUtil.closeStream(fis);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private boolean IsAIAInfoPresent(X509Certificate cert)
/*     */   {
/*     */     try
/*     */     {
/* 274 */       AuthorityInfoAccessExtension aia = X509CertImpl.toImpl(cert).getAuthorityInfoAccessExtension();
/*     */       
/* 276 */       return aia != null;
/*     */     }
/*     */     catch (CertificateException ce) {}
/* 279 */     return false;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/service/authenticator/ClientCertAuthenticator.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */